package com.transcargo.distance;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;

import com.transcargo.util.Converter;

public class Distance {
	public static class road {
		String point;
		int roadType;
		int distance;
		int distanceLong;
		int pointType;
	}
	public road[] Road = null;
	public int totalDistance;
	public String startCity = null;
	public String endCity = null;
	
	private static Logger logger = Logger.getLogger(Distance.class);
	private static final String server_url = "http://ati.su/Trace/PrintVersion.aspx?EntityType=Trace&printversion=true";
	
	private String getPage(String url) {
		String res = "";
		URL server = null;
		logger.debug("Fetching url: " + url);
		try {
			server = new URL(url);
			URLConnection sc = server.openConnection();
			BufferedReader in = new BufferedReader(new InputStreamReader(sc.getInputStream()));
			String inputLine;
			while ((inputLine = in.readLine()) != null) 
			res = res + inputLine;
			in.close();
		} catch (MalformedURLException e) {
			return null;
		} catch (IOException e) {
			return null;
		}
		return res;
	}
	private ArrayList<road> parsePage(String page) throws UnsupportedEncodingException, Exception {
		String[] strs = page.split("<span");
		Pattern p1 = Pattern.compile("\"[^\"]+\"");
		Pattern p2 = Pattern.compile(">[^<]+<");
		Pattern p3 = Pattern.compile("\\d+");
		ArrayList<road> pts = new ArrayList<road>(); 
		logger.debug("Items returned: " + (strs.length - 1));
		for (int i = 0; i < strs.length; i++) {
			Matcher m1 = p1.matcher(strs[i]);
			Matcher m2 = p2.matcher(strs[i]);
			String s1 = null,s2 = null;
			if (m1.find()) s1 = strs[i].substring(m1.start() + 1, m1.end() - 1); else throw new Exception("Unable to parse page 1");
			if (m2.find()) s2 = strs[i].substring(m2.start() + 1, m2.end() - 1); else throw new Exception("Unable to parse page 2");

			Boolean margin = s1.equals("font-weight:bold");
			if (s1 != null) if (s1.equals("atiTrace_lblTotalDistance")) {
				totalDistance = Integer.parseInt(s2);
				logger.debug("totalDistance: " + totalDistance);
			} else if (margin || s1.equals("font-weight:normal")) {
				road r = new road();
				r.point = Converter.Win1251ToUTF8(s2);
				r.distance = 0;
				r.distanceLong = totalDistance;
				String[] cells = strs[i].split("<td");
				Matcher m3 = p1.matcher((margin&&startCity==null)?cells[3]:cells[4]);
				if (m3.find() && m3.find()) {
					String img = m3.group();
					char c = img.charAt(img.length() - 6);
					r.pointType = c - '0';
				} else throw new Exception("Unable to parse page 3");
				m3 = p1.matcher(cells[5]);
				if (margin) {
					if (startCity == null) {
						startCity = Converter.Win1251ToUTF8(s2); 
						m3 = p1.matcher(cells[4]);
					} else endCity = Converter.Win1251ToUTF8(s2);
				}
				if (endCity == null) {
					if (m3.find() && m3.find()) {
						String img = m3.group();
						char c = img.charAt(img.length() - 6);
						r.roadType = c - '0';
					} else throw new Exception("Unable to parse page 4");
					m3 = p3.matcher(margin?cells[5]:cells[6]);
					if (m3.find()) r.distanceLong = Integer.parseInt(m3.group()); else throw new Exception("Unable to parse page 5");
					if (cells[11].contains("tdCountryName")) {
						if (cells[14].contains("tdTrassa")) m3 = p3.matcher(cells[20]);
						else m3 = p3.matcher(cells[19]); 
					} else {
						if (margin || !cells[14].contains("tdTrassa")) m3 = p3.matcher(cells[18]);
						else m3 = p3.matcher(cells[19]);
					}
					if (m3.find()) r.distance = Integer.parseInt(m3.group()); else throw new Exception("Unable to parse page 6");
				}
				m3 = p1.matcher(margin?cells[10]:cells[11]);
				if (m3.find() && m3.group().equals("\"tdCountryName\"")) {
					road r1 = new road();
					Matcher m4 = p2.matcher(margin?cells[10]:cells[11]);
					if (m4.find() && m4.find()) {
						r1.point = Converter.Win1251ToUTF8(m4.group().substring(1, m4.group().length() - 1));
						r1.roadType = (margin&&endCity==null)?0:r.roadType;
						r1.distance = 0;
						r1.distanceLong = 0;
						r1.pointType = 11;
						pts.add(r1);
						logger.debug("Country Name: " + r.point);
					} else throw new Exception("Unable to parse page 7");
				}
				int k = r.roadType;
				if (margin) if (endCity==null) r.roadType += 20; else r.roadType += 30;
				pts.add(r);
				logger.debug("Name: " + r.point + " distance: " + r.distance + " longDistance: " + r.distanceLong);
				if (strs[i].contains("!-- Region border --")) {
					String[] regs = strs[i].split("!-- Region border --");
					cells = regs[1].split("<td");
					Matcher m4 = p2.matcher(cells[8]);
					if (m4.find()) {
						road r1 = new road();
						r1.point = Converter.Win1251ToUTF8(m4.group().substring(1, m4.group().length() - 1));
						r1.roadType = k;
						r1.distance = 0;
						r1.distanceLong = 0;
						r1.pointType = 10;
						pts.add(r1);
						logger.debug("Region Name: " + r.point);
					}
				}
			}
		}
		return pts;
		
	}
	public void CalculateDistance(String cityFrom, String cityTo, Boolean fastWay, Boolean bigCities) throws Exception
	{
		String url = server_url + "&City1=" + URLEncoder.encode(cityFrom, "UTF-8") + "&City5=" + URLEncoder.encode(cityTo, "UTF-8");
		if (!fastWay) url = url + "&FastWay=false";
		if (bigCities) url = url + "&LargeCities=true";
		String page = getPage(url);
		if (page == null) throw new Exception("Unable to get page");
		ArrayList<road> pts = parsePage(page);
		Road = new road[pts.size()];
		pts.toArray(Road);
		for (int i = 0; i < Road.length; i++) if (i < Road.length - 1 && Road[i].pointType == 10 && Road[i+1].pointType == 11) {
			road r = Road[i];
			Road[i+1].roadType = r.roadType;
			Road[i] = Road[i+1];
			Road[i + 1] = r;
		}
	}

}
